﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Runtime.Serialization;

namespace CraigsCrawler
{
    public partial class SearchStorage
    {
        public static string StoragePath
        {
            get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CraigsCrawler"); }
        }

        public void Save()
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(SearchStorage));

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            string tempName = Path.GetTempFileName();
            using (FileStream stream = new FileStream(tempName, FileMode.OpenOrCreate))
            {
                serializer.WriteObject(stream, this);
            }

            if (File.Exists(filename)) File.Delete(filename);

            File.Move(tempName, filename);
        }

        public void Empty()
        {
            entries.Clear();
            entriesByUrl.Clear();

            foreach (FileInfo file in new FileInfo(filename).Directory.GetFiles("*.jpg"))
            {
                try
                {
                    File.Delete(file.FullName);
                }
                catch
                {
                }
            }
        }

        public void Delete()
        {
            Empty();
            try
            {
                File.Delete(filename);
            }
            catch
            {
            }
        }

        public static SearchStorage Load(string name)
        {
            string directory = Path.Combine(StoragePath, name);
            string filename = Path.Combine(directory, "SearchStorage.xml");

            if (File.Exists(filename))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(SearchStorage));
                using (FileStream stream = new FileStream(filename, FileMode.Open))
                {
                    SearchStorage loaded = (SearchStorage)serializer.ReadObject(stream);
                    loaded.filename = filename;
                    loaded.directory = directory;
                    loaded.Name = name;
                    return loaded;
                }
            }

            SearchStorage result = GetDefault();
            result.filename = filename;
            result.directory = directory;
            result.Name = name;
            result.Save();
            return result;
        }

        public static IEnumerable<SearchStorage> LoadAll()
        {
            List<SearchStorage> result = new List<SearchStorage>();

            DirectoryInfo directory = new DirectoryInfo(StoragePath);
            if (!directory.Exists)
            {
                return Enumerable.Empty<SearchStorage>();
            }

            foreach (DirectoryInfo subdir in directory.EnumerateDirectories())
            {
                try
                {
                    string filename = Path.Combine(subdir.FullName, "SearchStorage.xml");
                    if (File.Exists(filename))
                    {
                        SearchStorage storage = SearchStorage.Load(new FileInfo(filename).Directory.Name);
                        result.Add(storage);
                    }
                }
                catch (Exception e)
                {
                    MainWindow.WriteException("Failed to load search " + subdir.Name, e);
                }
            }

            return result.OrderBy(s => s.Name).ToList();
        }

        private static SearchStorage GetDefault()
        {
            ManualResetEvent waitHandle = new ManualResetEvent(false);
            SearchStorage result = new SearchStorage();
            MainWindow.WriteLine("Generating default state...");
            Querier.Current.RequestImmediately("http://www.craigslist.org/about/sites", (u, c) => Done(c, result, waitHandle), (u, e) => Failed(e, waitHandle));
            waitHandle.WaitOne();

            result.queryInterval = new TimeSpan(0, 0, 5);
            result.entries = new List<Entry>();
            result.suppressedTitles = new List<Tuple<string, string>>();

            result.OnDeserialized(new StreamingContext());

            return result;
        }

        private static void Done(Stream content, SearchStorage storage, ManualResetEvent waitHandle)
        {
            MainWindow.WriteLine("Downloaded list of cities.");

            storage.cities = Parse.LandingForCities(content).ToArray();

            waitHandle.Set();
        }

        private static void Failed(Exception e, ManualResetEvent waitHandle)
        {
            MainWindow.WriteException("Failed to download list of cities.", e);
            waitHandle.Set();
        }
    }
}
